﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace DARE
{
    public class CWtfCamera : CCamera
    {

    #region fields

        private float m_desiredChaseDistance = 10.0f;
        private float m_minChaseDistance = 5.0f;
        private float m_maxChaseDistance = 15.0f;
        private float m_chaseSpeed = 1.0f;
        private float m_maxRotate = 30.0f;

        private Vector3 m_chasePosition;
        private Vector3 m_chaseDirection;
        private Vector3 m_eyeRotate;
        private Vector3 m_eyeRotateVelocity = new Vector3(1.0f, 1.0f, 1.0f);
        private bool m_isFirstTimeChase = true;

    #endregion

    #region properties

        public Vector3 ChasePosition
        {
            get { return m_chasePosition; }
            set { m_chasePosition = value; }
        }

        public Vector3 ChaseDirection
        {
            get { return m_chaseDirection; }
            set { m_chaseDirection = value; }
        }

        public float MaxRotate
        {
            get { return m_maxRotate; }
            set { m_maxRotate = value; }
        }

        public Vector3 EyeRotateVelocity
        {
            get { return m_eyeRotateVelocity; }
            set { m_eyeRotateVelocity = value; }
        }

        public Vector3 EyeRotate
        {
            get { return m_eyeRotate; }
        }

    #endregion

    #region ctor

        // used to serialize
        public CWtfCamera() {}

        public CWtfCamera(string name) : base(name) {}

    #endregion

    #region methods

        public void SetChaseParameters(float chaseSpeed, float desiredChaseDistance, 
            float minChaseDistance, float maxChaseDistance)
        {
            m_chaseSpeed = chaseSpeed;
            m_desiredChaseDistance = desiredChaseDistance;
            m_minChaseDistance = minChaseDistance;
            m_maxChaseDistance = maxChaseDistance;
        }

        Vector3 targetPosition;

        private void UpdateFollowPosition(float elapsedTimeSeconds, bool interpolate)
        {
            float interpolatedSpeed = MathHelper.Clamp(m_chaseSpeed * elapsedTimeSeconds, 0.0f, 1.0f);

            // wrong for the target position, should not be the node
            if (!interpolate)
                targetPosition = m_chasePosition;
            else
                targetPosition = Vector3.Lerp(targetPosition, m_chasePosition, interpolatedSpeed);

            Vector3 desiredCameraPosition = m_chasePosition - m_chaseDirection * m_desiredChaseDistance;

            if (interpolate)
            {
                desiredCameraPosition = Vector3.Lerp(m_position, desiredCameraPosition, interpolatedSpeed);
                Vector3 targetVector = desiredCameraPosition - targetPosition;
                float targetLength = targetVector.Length();
                targetVector /= targetLength;

                if (targetLength < m_minChaseDistance)
                    desiredCameraPosition = targetPosition + targetVector * m_minChaseDistance;
                else if (targetLength > m_maxChaseDistance)
                    desiredCameraPosition = targetPosition + targetVector * m_maxChaseDistance;
            }
            SetLookAt(desiredCameraPosition, targetPosition, m_up);
        }

        public override void Update(GameTime gameTime)
        {
            float time = gameTime.ElapsedGameTime.Milliseconds / 1000.0f;

            UpdateFollowPosition(time, !m_isFirstTimeChase);
            if (m_isFirstTimeChase)
            {
                m_eyeRotate = Vector3.Zero;
                m_isFirstTimeChase = false;
            }

            //if (m_eyeRotateVelocity != Vector3.Zero)
            //{
            //    m_eyeRotate += m_eyeRotateVelocity * time;
            //    m_eyeRotate.X = MathHelper.Clamp(m_eyeRotate.X, -m_maxRotate, m_maxRotate);
            //    m_eyeRotate.Y = MathHelper.Clamp(m_eyeRotate.Y, -m_maxRotate, m_maxRotate);
            //    m_eyeRotate.Z = MathHelper.Clamp(m_eyeRotate.Z, -m_maxRotate, m_maxRotate);
            //    m_needUpdateView = true;
            //}
        }

        protected override void UpdateView()
        {
            Vector3 newPosition = m_position - m_target;

            //newPosition = Vector3.Transform(newPosition, 
            //    Matrix.CreateFromAxisAngle(m_upVector, MathHelper.ToRadians(m_eyeRotate.Y)) * 
            //    Matrix.CreateFromAxisAngle(m_strafeVector, MathHelper.ToRadians(m_eyeRotate.X)) * 
            //    Matrix.CreateFromAxisAngle(m_headingVector, MathHelper.ToRadians(m_headingVector.Z)));

            m_viewMatrix = Matrix.CreateLookAt(newPosition + m_target, m_target, m_up);

            m_needUpdateView = false;
            m_needUpdateFrustrum = true;
        }

    #endregion

    }
}
